home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / rcp / rcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-03  |  20.7 KB  |  991 lines

  1. /*
  2.  * Copyright (c) 1983, 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)rcp.c    5.32 (Berkeley) 2/25/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * rcp
  46.  */
  47. #include <sys/param.h>
  48. #include <sys/stat.h>
  49. #include <sys/time.h>
  50. #include <sys/ioctl.h>
  51. #include <sys/socket.h>
  52. #include <sys/wait.h>
  53. #include <netinet/in.h>
  54. #include <netinet/in_systm.h>
  55. #include <netinet/ip.h>
  56. #include <dirent.h>
  57. #include <fcntl.h>
  58. #include <signal.h>
  59. #include <pwd.h>
  60. #include <netdb.h>
  61. #include <errno.h>
  62. #include <unistd.h>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66. #include <ctype.h>
  67. #include <sys/dir.h>
  68. #include "pathnames.h"
  69.  
  70. #ifdef KERBEROS
  71. #include <kerberosIV/des.h>
  72. #include <kerberosIV/krb.h>
  73. char    dst_realm_buf[REALM_SZ];
  74. char    *dest_realm = NULL;
  75. int    use_kerberos = 1;
  76. CREDENTIALS     cred;
  77. Key_schedule    schedule;
  78. extern    char    *krb_realmofhost();
  79. #ifdef CRYPT
  80. int    doencrypt = 0;
  81. #define    OPTIONS    "dfk:prtx"
  82. #else
  83. #define    OPTIONS    "dfk:prt"
  84. #endif
  85. #else
  86. #define    OPTIONS "dfprt"
  87. #endif
  88.  
  89. struct passwd *pwd;
  90. u_short    port;
  91. uid_t    userid;
  92. int errs, rem;
  93. int pflag, iamremote, iamrecursive, targetshouldbedirectory;
  94.  
  95. #define    CMDNEEDS    64
  96. char cmd[CMDNEEDS];        /* must hold "rcp -r -p -d\0" */
  97.  
  98. typedef struct _buf {
  99.     int    cnt;
  100.     char    *buf;
  101. } BUF;
  102.  
  103. void lostconn();
  104.  
  105. main(argc, argv)
  106.     int argc;
  107.     char **argv;
  108. {
  109.     extern int optind;
  110.     extern char *optarg;
  111.     struct servent *sp;
  112.     int ch, fflag, tflag;
  113.     char *targ, *shell, *colon();
  114.  
  115.     fflag = tflag = 0;
  116.     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
  117.         switch(ch) {
  118.         /* user-visible flags */
  119.         case 'p':            /* preserve access/mod times */
  120.             ++pflag;
  121.             break;
  122.         case 'r':
  123.             ++iamrecursive;
  124.             break;
  125. #ifdef    KERBEROS
  126.         case 'k':
  127.             strncpy(dst_realm_buf, optarg, REALM_SZ);
  128.             dest_realm = dst_realm_buf;
  129.             break;
  130. #ifdef CRYPT
  131.         case 'x':
  132.             doencrypt = 1;
  133.             /* des_set_key(cred.session, schedule); */
  134.             break;
  135. #endif
  136. #endif
  137.         /* rshd-invoked options (server) */
  138.         case 'd':
  139.             targetshouldbedirectory = 1;
  140.             break;
  141.         case 'f':            /* "from" */
  142.             iamremote = 1;
  143.             fflag = 1;
  144.             break;
  145.         case 't':            /* "to" */
  146.             iamremote = 1;
  147.             tflag = 1;
  148.             break;
  149.  
  150.         case '?':
  151.         default:
  152.             usage();
  153.         }
  154.     argc -= optind;
  155.     argv += optind;
  156.  
  157. #ifdef KERBEROS
  158. #ifdef CRYPT
  159.     shell = doencrypt ? "ekshell" : "kshell";
  160. #else
  161.     shell = "kshell";
  162. #endif
  163.     sp = getservbyname(shell, "tcp");
  164.     if (sp == NULL) {
  165.         char    msgbuf[64];
  166.         use_kerberos = 0;
  167.         (void)sprintf(msgbuf,
  168.             "can't get entry for %s/tcp service", shell);
  169.         old_warning(msgbuf);
  170.         sp = getservbyname(shell = "shell", "tcp");
  171.     }
  172. #else
  173.     sp = getservbyname(shell = "shell", "tcp");
  174. #endif
  175.     if (sp == NULL) {
  176.         (void)fprintf(stderr, "rcp: %s/tcp: unknown service\n", shell);
  177.         exit(1);
  178.     }
  179.     port = sp->s_port;
  180.  
  181.     if (!(pwd = getpwuid(userid = getuid()))) {
  182.         (void)fprintf(stderr, "rcp: unknown user %d.\n", (int)userid);
  183.         exit(1);
  184.     }
  185.  
  186.     if (fflag) {
  187.         /* follow "protocol", send data */
  188.         (void)response();
  189.         (void)setuid(userid);
  190.         source(argc, argv);
  191.         exit(errs);
  192.     }
  193.  
  194.     if (tflag) {
  195.         /* receive data */
  196.         (void)setuid(userid);
  197.         sink(argc, argv);
  198.         exit(errs);
  199.     }
  200.  
  201.     if (argc < 2)
  202.         usage();
  203.     if (argc > 2)
  204.         targetshouldbedirectory = 1;
  205.  
  206.     rem = -1;
  207.     /* command to be executed on remote system using "rsh" */
  208. #ifdef    KERBEROS
  209.     (void)sprintf(cmd,
  210.         "rcp%s%s%s%s", iamrecursive ? " -r" : "",
  211. #ifdef CRYPT
  212.         ((doencrypt && use_kerberos) ? " -x" : ""),
  213. #else
  214.         "",
  215. #endif
  216.         pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
  217. #else
  218.     (void)sprintf(cmd, "rcp%s%s%s",
  219.         iamrecursive ? " -r" : "", pflag ? " -p" : "",
  220.         targetshouldbedirectory ? " -d" : "");
  221. #endif
  222.  
  223.     (void)signal(SIGPIPE, lostconn);
  224.  
  225.     if (targ = colon(argv[argc - 1]))
  226.         toremote(targ, argc, argv);    /* destination is remote host */
  227.     else {
  228.         tolocal(argc, argv);        /* destination is local host */
  229.         if (targetshouldbedirectory)
  230.             verifydir(argv[argc - 1]);
  231.     }
  232.     exit(errs);
  233. }
  234.  
  235. toremote(targ, argc, argv)
  236.     char *targ;
  237.     int argc;
  238.     char **argv;
  239. {
  240.     int i, len, tos;
  241.     char *bp, *host, *src, *suser, *thost, *tuser;
  242.     char *colon();
  243.  
  244.     *targ++ = 0;
  245.     if (*targ == 0)
  246.         targ = ".";
  247.  
  248.     if (thost = index(argv[argc - 1], '@')) {
  249.         /* user@host */
  250.         *thost++ = 0;
  251.         tuser = argv[argc - 1];
  252.         if (*tuser == '\0')
  253.             tuser = NULL;
  254.         else if (!okname(tuser))
  255.             exit(1);
  256.     } else {
  257.         thost = argv[argc - 1];
  258.         tuser = NULL;
  259.     }
  260.  
  261.     for (i = 0; i < argc - 1; i++) {
  262.         src = colon(argv[i]);
  263.         if (src) {            /* remote to remote */
  264.             *src++ = 0;
  265.             if (*src == 0)
  266.                 src = ".";
  267.             host = index(argv[i], '@');
  268.             len = strlen(_PATH_RSH) + strlen(argv[i]) +
  269.                 strlen(src) + (tuser ? strlen(tuser) : 0) +
  270.                 strlen(thost) + strlen(targ) + CMDNEEDS + 20;
  271.             if (!(bp = malloc(len)))
  272.                 nospace();
  273.             if (host) {
  274.                 *host++ = 0;
  275.                 suser = argv[i];
  276.                 if (*suser == '\0')
  277.                     suser = pwd->pw_name;
  278.                 else if (!okname(suser))
  279.                     continue;
  280.                 (void)sprintf(bp,
  281.                     "%s %s -l %s -n %s %s '%s%s%s:%s'",
  282.                     _PATH_RSH, host, suser, cmd, src,
  283.                     tuser ? tuser : "", tuser ? "@" : "",
  284.                     thost, targ);
  285.             } else
  286.                 (void)sprintf(bp,
  287.                     "%s %s -n %s %s '%s%s%s:%s'",
  288.                     _PATH_RSH, argv[i], cmd, src,
  289.                     tuser ? tuser : "", tuser ? "@" : "",
  290.                     thost, targ);
  291.             (void)susystem(bp);
  292.             (void)free(bp);
  293.         } else {            /* local to remote */
  294.             if (rem == -1) {
  295.                 len = strlen(targ) + CMDNEEDS + 20;
  296.                 if (!(bp = malloc(len)))
  297.                     nospace();
  298.                 (void)sprintf(bp, "%s -t %s", cmd, targ);
  299.                 host = thost;
  300. #ifdef KERBEROS
  301.                 if (use_kerberos)
  302.                     rem = kerberos(&host, bp,
  303.                         pwd->pw_name,
  304.                         tuser ? tuser : pwd->pw_name);
  305.                 else
  306. #endif
  307.                     rem = rcmd(&host, port, pwd->pw_name,
  308.                         tuser ? tuser : pwd->pw_name,
  309.                         bp, 0);
  310.                 if (rem < 0)
  311.                     exit(1);
  312. #if 0
  313.                 tos = IPTOS_THROUGHPUT;
  314.                 if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  315.                     (char *)&tos, sizeof(int)) < 0)
  316.                     perror("rcp: setsockopt TOS (ignored)");
  317. #endif
  318.                 if (response() < 0)
  319.                     exit(1);
  320.                 (void)free(bp);
  321.                 (void)setuid(userid);
  322.             }
  323.             source(1, argv+i);
  324.         }
  325.     }
  326. }
  327.  
  328. tolocal(argc, argv)
  329.     int argc;
  330.     char **argv;
  331. {
  332.     int i, len, tos;
  333.     char *bp, *host, *src, *suser;
  334.     char *colon();
  335.  
  336.     for (i = 0; i < argc - 1; i++) {
  337.         if (!(src = colon(argv[i]))) {    /* local to local */
  338.             len = strlen(_PATH_CP) + strlen(argv[i]) +
  339.                 strlen(argv[argc - 1]) + 20;
  340.             if (!(bp = malloc(len)))
  341.                 nospace();
  342.             (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP,
  343.                 iamrecursive ? " -r" : "", pflag ? " -p" : "",
  344.                 argv[i], argv[argc - 1]);
  345.             (void)susystem(bp);
  346.             (void)free(bp);
  347.             continue;
  348.         }
  349.         *src++ = 0;
  350.         if (*src == 0)
  351.             src = ".";
  352.         host = index(argv[i], '@');
  353.         if (host) {
  354.             *host++ = 0;
  355.             suser = argv[i];
  356.             if (*suser == '\0')
  357.                 suser = pwd->pw_name;
  358.             else if (!okname(suser))
  359.                 continue;
  360.         } else {
  361.             host = argv[i];
  362.             suser = pwd->pw_name;
  363.         }
  364.         len = strlen(src) + CMDNEEDS + 20;
  365.         if (!(bp = malloc(len)))
  366.             nospace();
  367.         (void)sprintf(bp, "%s -f %s", cmd, src);
  368. #ifdef KERBEROS
  369.         if (use_kerberos)
  370.             rem = kerberos(&host, bp, pwd->pw_name, suser);
  371.         else
  372. #endif
  373.             rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0);
  374.         (void)free(bp);
  375.         if (rem < 0)
  376.             continue;
  377.         (void)seteuid(userid);
  378. #if 0
  379.         tos = IPTOS_THROUGHPUT;
  380.         if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  381.             (char *)&tos, sizeof(int)) < 0)
  382.             perror("rcp: setsockopt TOS (ignored)");
  383. #endif
  384.         sink(1, argv + argc - 1);
  385.         (void)seteuid(0);
  386.         (void)close(rem);
  387.         rem = -1;
  388.     }
  389. }
  390.  
  391. verifydir(cp)
  392.     char *cp;
  393. {
  394.     struct stat stb;
  395.  
  396.     if (stat(cp, &stb) >= 0) {
  397.         if ((stb.st_mode & S_IFMT) == S_IFDIR)
  398.             return;
  399.         errno = ENOTDIR;
  400.     }
  401.     error("rcp: %s: %s.\n", cp, strerror(errno));
  402.     exit(1);
  403. }
  404.  
  405. char *
  406. colon(cp)
  407.     register char *cp;
  408. {
  409.     for (; *cp; ++cp) {
  410.         if (*cp == ':')
  411.             return(cp);
  412.         if (*cp == '/')
  413.             return(0);
  414.     }
  415.     return(0);
  416. }
  417.  
  418. okname(cp0)
  419.     char *cp0;
  420. {
  421.     register char *cp = cp0;
  422.     register int c;
  423.  
  424.     do {
  425.         c = *cp;
  426.         if (c & 0200)
  427.             goto bad;
  428.         if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
  429.             goto bad;
  430.     } while (*++cp);
  431.     return(1);
  432. bad:
  433.     (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0);
  434.     return(0);
  435. }
  436.  
  437.  
  438. susystem(s)
  439.     char *s;
  440. {
  441.     int status, pid, w;
  442.     register int istat, qstat;
  443.  
  444.     if ((pid = vfork()) == 0) {
  445.         (void)setuid(userid);
  446.         execl(_PATH_BSHELL, "sh", "-c", s, (char *)0);
  447.         _exit(127);
  448.     }
  449.     istat = signal(SIGINT, SIG_IGN);
  450.     qstat = signal(SIGQUIT, SIG_IGN);
  451.     while ((w = wait(&status)) != pid && w != -1)
  452.         ;
  453.     if (w == -1)
  454.         status = -1;
  455.     (void)signal(SIGINT, istat);
  456.     (void)signal(SIGQUIT, qstat);
  457.     return(status);
  458. }
  459.  
  460. source(argc, argv)
  461.     int argc;
  462.     char **argv;
  463. {
  464.     struct stat stb;
  465.     static BUF buffer;
  466.     BUF *bp;
  467.     off_t i;
  468.     int x, readerr, f, amt;
  469.     char *last, *name, buf[BUFSIZ];
  470.     BUF *allocbuf();
  471.  
  472.     for (x = 0; x < argc; x++) {
  473.         name = argv[x];
  474.         if ((f = open(name, O_RDONLY, 0)) < 0) {
  475.             error("rcp: %s: %s\n", name, strerror(errno));
  476.             continue;
  477.         }
  478.         if (fstat(f, &stb) < 0)
  479.             goto notreg;
  480.         switch (stb.st_mode&S_IFMT) {
  481.  
  482.         case S_IFREG:
  483.             break;
  484.  
  485.         case S_IFDIR:
  486.             if (iamrecursive) {
  487.                 (void)close(f);
  488.                 rsource(name, &stb);
  489.                 continue;
  490.             }
  491.             /* FALLTHROUGH */
  492.         default:
  493. notreg:            (void)close(f);
  494.             error("rcp: %s: not a plain file\n", name);
  495.             continue;
  496.         }
  497.         last = rindex(name, '/');
  498.         if (last == 0)
  499.             last = name;
  500.         else
  501.             last++;
  502.         if (pflag) {
  503.             /*
  504.              * Make it compatible with possible future
  505.              * versions expecting microseconds.
  506.              */
  507.             (void)sprintf(buf,
  508.                 "T%ld 0 %ld 0\n", stb.st_mtime, stb.st_atime);
  509.             (void)write(rem, buf, (int)strlen(buf));
  510.             if (response() < 0) {
  511.                 (void)close(f);
  512.                 continue;
  513.             }
  514.         }
  515.         (void)sprintf(buf,
  516.             "C%04o %ld %s\n", stb.st_mode&07777, stb.st_size, last);
  517.         (void)write(rem, buf, (int)strlen(buf));
  518.         if (response() < 0) {
  519.             (void)close(f);
  520.             continue;
  521.         }
  522.         if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
  523.             (void)close(f);
  524.             continue;
  525.         }
  526.         readerr = 0;
  527.         for (i = 0; i < stb.st_size; i += bp->cnt) {
  528.             amt = bp->cnt;
  529.             if (i + amt > stb.st_size)
  530.                 amt = stb.st_size - i;
  531.             if (readerr == 0 && read(f, bp->buf, amt) != amt)
  532.                 readerr = errno;
  533.             (void)write(rem, bp->buf, amt);
  534.         }
  535.         (void)close(f);
  536.         if (readerr == 0)
  537.             (void)write(rem, "", 1);
  538.         else
  539.             error("rcp: %s: %s\n", name, strerror(readerr));
  540.         (void)response();
  541.     }
  542. }
  543.  
  544. rsource(name, statp)
  545.     char *name;
  546.     struct stat *statp;
  547. {
  548.     DIR *dirp;
  549.     struct direct *dp;
  550.     char *last, *vect[1], path[MAXPATHLEN];
  551.  
  552.     if (!(dirp = opendir(name))) {
  553.         error("rcp: %s: %s\n", name, strerror(errno));
  554.         return;
  555.     }
  556.     last = rindex(name, '/');
  557.     if (last == 0)
  558.         last = name;
  559.     else
  560.         last++;
  561.     if (pflag) {
  562.         (void)sprintf(path,
  563.             "T%ld 0 %ld 0\n", statp->st_mtime, statp->st_atime);
  564.         (void)write(rem, path, (int)strlen(path));
  565.         if (response() < 0) {
  566.             closedir(dirp);
  567.             return;
  568.         }
  569.     }
  570.     (void)sprintf(path,
  571.         "D%04o %d %s\n", statp->st_mode&07777, 0, last);
  572.     (void)write(rem, path, (int)strlen(path));
  573.     if (response() < 0) {
  574.         closedir(dirp);
  575.         return;
  576.     }
  577.     while (dp = readdir(dirp)) {
  578.         if (dp->d_ino == 0)
  579.             continue;
  580.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  581.             continue;
  582.         if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
  583.             error("%s/%s: name too long.\n", name, dp->d_name);
  584.             continue;
  585.         }
  586.         (void)sprintf(path, "%s/%s", name, dp->d_name);
  587.         vect[0] = path;
  588.         source(1, vect);
  589.     }
  590.     closedir(dirp);
  591.     (void)write(rem, "E\n", 2);
  592.     (void)response();
  593. }
  594.  
  595. response()
  596. {
  597.     register char *cp;
  598.     char ch, resp, rbuf[BUFSIZ];
  599.  
  600.     if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
  601.         lostconn();
  602.  
  603.     cp = rbuf;
  604.     switch(resp) {
  605.     case 0:                /* ok */
  606.         return(0);
  607.     default:
  608.         *cp++ = resp;
  609.         /* FALLTHROUGH */
  610.     case 1:                /* error, followed by err msg */
  611.     case 2:                /* fatal error, "" */
  612.         do {
  613.             if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  614.                 lostconn();
  615.             *cp++ = ch;
  616.         } while (cp < &rbuf[BUFSIZ] && ch != '\n');
  617.  
  618.         if (!iamremote)
  619.             (void)write(2, rbuf, cp - rbuf);
  620.         ++errs;
  621.         if (resp == 1)
  622.             return(-1);
  623.         exit(1);
  624.     }
  625.     /*NOTREACHED*/
  626. }
  627.  
  628. void
  629. lostconn()
  630. {
  631.     if (!iamremote)
  632.         (void)fprintf(stderr, "rcp: lost connection\n");
  633.     exit(1);
  634. }
  635.  
  636. sink(argc, argv)
  637.     int argc;
  638.     char **argv;
  639. {
  640.     register char *cp;
  641.     static BUF buffer;
  642.     struct stat stb;
  643.     struct timeval tv[2];
  644.     enum { YES, NO, DISPLAYED } wrerr;
  645.     BUF *bp, *allocbuf();
  646.     off_t i, j;
  647.     char ch, *targ, *why;
  648.     int amt, count, exists, first, mask, mode;
  649.     int ofd, setimes, size, targisdir;
  650.     char *np, *vect[1], buf[BUFSIZ];
  651.  
  652. #define    atime    tv[0]
  653. #define    mtime    tv[1]
  654. #define    SCREWUP(str)    { why = str; goto screwup; }
  655.  
  656.     setimes = targisdir = 0;
  657.     mask = umask(0);
  658.     if (!pflag)
  659.         (void)umask(mask);
  660.     if (argc != 1) {
  661.         error("rcp: ambiguous target\n");
  662.         exit(1);
  663.     }
  664.     targ = *argv;
  665.     if (targetshouldbedirectory)
  666.         verifydir(targ);
  667.     (void)write(rem, "", 1);
  668.     if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
  669.         targisdir = 1;
  670.     for (first = 1;; first = 0) {
  671.         cp = buf;
  672.         if (read(rem, cp, 1) <= 0)
  673.             return;
  674.         if (*cp++ == '\n')
  675.             SCREWUP("unexpected <newline>");
  676.         do {
  677.             if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  678.                 SCREWUP("lost connection");
  679.             *cp++ = ch;
  680.         } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
  681.         *cp = 0;
  682.  
  683.         if (buf[0] == '\01' || buf[0] == '\02') {
  684.             if (iamremote == 0)
  685.                 (void)write(2, buf + 1, (int)strlen(buf + 1));
  686.             if (buf[0] == '\02')
  687.                 exit(1);
  688.             errs++;
  689.             continue;
  690.         }
  691.         if (buf[0] == 'E') {
  692.             (void)write(rem, "", 1);
  693.             return;
  694.         }
  695.  
  696.         if (ch == '\n')
  697.             *--cp = 0;
  698.  
  699. #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
  700.         cp = buf;
  701.         if (*cp == 'T') {
  702.             setimes++;
  703.             cp++;
  704.             getnum(mtime.tv_sec);
  705.             if (*cp++ != ' ')
  706.                 SCREWUP("mtime.sec not delimited");
  707.             getnum(mtime.tv_usec);
  708.             if (*cp++ != ' ')
  709.                 SCREWUP("mtime.usec not delimited");
  710.             getnum(atime.tv_sec);
  711.             if (*cp++ != ' ')
  712.                 SCREWUP("atime.sec not delimited");
  713.             getnum(atime.tv_usec);
  714.             if (*cp++ != '\0')
  715.                 SCREWUP("atime.usec not delimited");
  716.             (void)write(rem, "", 1);
  717.             continue;
  718.         }
  719.         if (*cp != 'C' && *cp != 'D') {
  720.             /*
  721.              * Check for the case "rcp remote:foo\* local:bar".
  722.              * In this case, the line "No match." can be returned
  723.              * by the shell before the rcp command on the remote is
  724.              * executed so the ^Aerror_message convention isn't
  725.              * followed.
  726.              */
  727.             if (first) {
  728.                 error("%s\n", cp);
  729.                 exit(1);
  730.             }
  731.             SCREWUP("expected control record");
  732.         }
  733.         mode = 0;
  734.         for (++cp; cp < buf + 5; cp++) {
  735.             if (*cp < '0' || *cp > '7')
  736.                 SCREWUP("bad mode");
  737.             mode = (mode << 3) | (*cp - '0');
  738.         }
  739.         if (*cp++ != ' ')
  740.             SCREWUP("mode not delimited");
  741.         size = 0;
  742.         while (isdigit(*cp))
  743.             size = size * 10 + (*cp++ - '0');
  744.         if (*cp++ != ' ')
  745.             SCREWUP("size not delimited");
  746.         if (targisdir) {
  747.             static char *namebuf;
  748.             static int cursize;
  749.             size_t need;
  750.  
  751.             need = strlen(targ) + strlen(cp) + 250;
  752.             if (need > cursize) {
  753.                 if (!(namebuf = malloc(need)))
  754.                     error("out of memory\n");
  755.             }
  756.             (void)sprintf(namebuf, "%s%s%s", targ,
  757.                 *targ ? "/" : "", cp);
  758.             np = namebuf;
  759.         }
  760.         else
  761.             np = targ;
  762.         exists = stat(np, &stb) == 0;
  763.         if (buf[0] == 'D') {
  764.             if (exists) {
  765.                 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
  766.                     errno = ENOTDIR;
  767.                     goto bad;
  768.                 }
  769.                 if (pflag)
  770.                     (void)chmod(np, mode);
  771.             } else if (mkdir(np, mode) < 0)
  772.                 goto bad;
  773.             vect[0] = np;
  774.             sink(1, vect);
  775.             if (setimes) {
  776.                 setimes = 0;
  777.                 if (utimes(np, tv) < 0)
  778.                     error("rcp: can't set times on %s: %s\n",
  779.                     np, strerror(errno));
  780.             }
  781.             continue;
  782.         }
  783.         if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
  784. bad:            error("rcp: %s: %s\n", np, strerror(errno));
  785.             continue;
  786.         }
  787.         if (exists && pflag)
  788.             (void)fchmod(ofd, mode);
  789.         (void)write(rem, "", 1);
  790.         if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) {
  791.             (void)close(ofd);
  792.             continue;
  793.         }
  794.         cp = bp->buf;
  795.         count = 0;
  796.         wrerr = NO;
  797.         for (i = 0; i < size; i += BUFSIZ) {
  798.             amt = BUFSIZ;
  799.             if (i + amt > size)
  800.                 amt = size - i;
  801.             count += amt;
  802.             do {
  803.                 j = read(rem, cp, amt);
  804.                 if (j <= 0) {
  805.                     error("rcp: %s\n",
  806.                         j ? strerror(errno) :
  807.                         "dropped connection");
  808.                     exit(1);
  809.                 }
  810.                 amt -= j;
  811.                 cp += j;
  812.             } while (amt > 0);
  813.             if (count == bp->cnt) {
  814.                 if (wrerr == NO &&
  815.                     write(ofd, bp->buf, count) != count)
  816.                     wrerr = YES;
  817.                 count = 0;
  818.                 cp = bp->buf;
  819.             }
  820.         }
  821.         if (count != 0 && wrerr == NO &&
  822.             write(ofd, bp->buf, count) != count)
  823.             wrerr = YES;
  824.         if (ftruncate(ofd, size)) {
  825.             error("rcp: can't truncate %s: %s\n", np,
  826.                 strerror(errno));
  827.             wrerr = DISPLAYED;
  828.         }
  829.         (void)close(ofd);
  830.         (void)response();
  831.         if (setimes && wrerr == NO) {
  832.             setimes = 0;
  833.             if (utimes(np, tv) < 0) {
  834.                 error("rcp: can't set times on %s: %s\n",
  835.                     np, strerror(errno));
  836.                 wrerr = DISPLAYED;
  837.             }
  838.         }
  839.         switch(wrerr) {
  840.         case YES:
  841.             error("rcp: %s: %s\n", np, strerror(errno));
  842.             break;
  843.         case NO:
  844.             (void)write(rem, "", 1);
  845.             break;
  846.         case DISPLAYED:
  847.             break;
  848.         }
  849.     }
  850. screwup:
  851.     error("rcp: protocol screwup: %s\n", why);
  852.     exit(1);
  853. }
  854.  
  855. BUF *
  856. allocbuf(bp, fd, blksize)
  857.     BUF *bp;
  858.     int fd, blksize;
  859. {
  860.     struct stat stb;
  861.     size_t size;
  862.  
  863.     if (fstat(fd, &stb) < 0) {
  864.         error("rcp: fstat: %s\n", strerror(errno));
  865.         return(0);
  866.     }
  867.     size = roundup(stb.st_blksize, blksize);
  868.     if (size == 0)
  869.         size = blksize;
  870.     if (bp->cnt < size) {
  871.         if (bp->buf != 0)
  872.             free(bp->buf);
  873.         bp->buf = malloc(size);
  874.         if (!bp->buf) {
  875.             error("rcp: malloc: out of memory\n");
  876.             return(0);
  877.         }
  878.     }
  879.     bp->cnt = size;
  880.     return(bp);
  881. }
  882.  
  883. /* VARARGS1 */
  884. error(fmt, a1, a2, a3)
  885.     char *fmt;
  886.     int a1, a2, a3;
  887. {
  888.     static FILE *fp;
  889.  
  890.     ++errs;
  891.     if (!fp && !(fp = fdopen(rem, "w")))
  892.         return;
  893.     (void)fprintf(fp, "%c", 0x01);
  894.     (void)fprintf(fp, fmt, a1, a2, a3);
  895.     (void)fflush(fp);
  896.     if (!iamremote)
  897.         (void)fprintf(stderr, fmt, a1, a2, a3);
  898. }
  899.  
  900. nospace()
  901. {
  902.     (void)fprintf(stderr, "rcp: out of memory.\n");
  903.     exit(1);
  904. }
  905.  
  906.  
  907. usage()
  908. {
  909. #ifdef KERBEROS
  910. #ifdef CRYPT
  911.     (void)fprintf(stderr, "%s\n\t%s\n",
  912.         "usage: rcp [-k realm] [-px] f1 f2",
  913.         "or: rcp [-k realm] [-rpx] f1 ... fn directory");
  914. #else
  915.     (void)fprintf(stderr, "%s\n\t%s\n",
  916.         "usage: rcp [-k realm] [-p] f1 f2",
  917.         "or: rcp [-k realm] [-rp] f1 ... fn directory");
  918. #endif
  919. #else
  920.     (void)fprintf(stderr,
  921.         "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n");
  922. #endif
  923.     exit(1);
  924. }
  925.  
  926. #ifdef KERBEROS
  927. old_warning(str)
  928.     char *str;
  929. {
  930.     (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str);
  931. }
  932.  
  933. int
  934. kerberos(host, bp, locuser, user)
  935.  
  936.     char **host, *bp, *locuser, *user;
  937. {
  938.     struct servent *sp;
  939.  
  940. again:
  941.     if (use_kerberos) {
  942.         rem = KSUCCESS;
  943.         errno = 0;
  944.         if (dest_realm == NULL)
  945.             dest_realm = krb_realmofhost(*host);
  946.  
  947. #ifdef CRYPT
  948.         if (doencrypt)
  949.             rem = krcmd_mutual(
  950.                 host, port,
  951.                 user, bp, 0,
  952.                     dest_realm,
  953.                 &cred, schedule);
  954.         else
  955. #endif
  956.             rem = krcmd(
  957.                 host, port,
  958.                 user, bp, 0, dest_realm);
  959.  
  960.         if (rem < 0) {
  961.             use_kerberos = 0;
  962.             sp = getservbyname("shell", "tcp");
  963.             if (sp == NULL) {
  964.                 (void)fprintf(stderr,
  965.                         "rcp: unknown service shell/tcp\n");
  966.                 exit(1);
  967.             }
  968.             if (errno == ECONNREFUSED)
  969.                 old_warning(
  970.                     "remote host doesn't support Kerberos");
  971.  
  972.             if (errno == ENOENT)
  973.                 old_warning(
  974.                     "Can't provide Kerberos auth data");
  975.             port = sp->s_port;
  976.             goto again;
  977.         }
  978.     } else {
  979. #ifdef CRYPT
  980.         if (doencrypt) {
  981.             fprintf(stderr,
  982.                 "The -x option requires Kerberos authentication\n");
  983.             exit(1);
  984.         }
  985. #endif
  986.         rem = rcmd(host, sp->s_port, locuser, user, bp, 0);
  987.     }
  988.     return(rem);
  989. }
  990. #endif /* KERBEROS */
  991.